package com.linkdood.app.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.jayway.jsonpath.JsonPath;
import com.linkdood.app.domain.ThirdParty;
import com.linkdood.app.dto.DdioUrlStatusDTO;
import com.linkdood.app.dto.ThirdPartyDTO;
import com.linkdood.app.service.DdioCheckService;
import com.linkdood.app.service.DdioService;
import com.linkdood.app.service.TokenService;
import com.linkdood.app.service.ddio.DdioResponseBody;
import com.linkdood.app.service.dto.DoodFriendsDTO;
import com.linkdood.app.utils.DdioUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * DDIO 接口校验
 *
 * @author YunJ
 */
@Slf4j
@Service
public class DdioCheckServiceImpl implements DdioCheckService {

    private static final String ACCESS_TOKEN = "access_token";

    /**
     * ddio 接口正确
     */
    private static final String DDIO_STATUS_OK = "ok";

    /**
     * 请求失败, http status 返回不为 200
     */
    private static final String DDIO_STATUS_HTTP_REQUEST_FAILED = "http_request_failed";

    /**
     * 请求失败, code 返回不为 0
     */
    private static final String DDIO_STATUS_REQUEST_FAILED = "request_failed";

    /**
     * 参数错误
     */
    private static final String DDIO_STATUS_RESPONSE_PARAM_ERROR = "response_param_error";

    /**
     * 返回值为空
     */
    private static final String DDIO_STATUS_RESPONSE_PARAM_EMPTY = "response_param_empty";


    private final DdioService ddioService;

    private final TokenService tokenService;

    public DdioCheckServiceImpl(DdioService ddioService, TokenService tokenService) {
        this.ddioService = ddioService;
        this.tokenService = tokenService;
    }


    /**
     * 获取服务器配置信息是否可用
     */
    @Override
    public Map<String, String> getStatus(ThirdPartyDTO thirdPartyDTO) {
        ThirdParty thirdParty = new ThirdParty();
        thirdParty.setServerUrl(thirdPartyDTO.getServerUrl());
        thirdParty.setAppId(thirdPartyDTO.getAppId());
        thirdParty.setAppSecret(thirdPartyDTO.getAppSecret());

        DdioUrlStatusDTO accessTokenStatus = getAccessTokenStatus(thirdParty);
        Map<String, String> result = new HashMap<>(2);
        if (!DDIO_STATUS_OK.equals(accessTokenStatus.getStatus())) {
            result.put("status", "error");
            result.put("msg", accessTokenStatus.getMsg());
        } else {
            result.put("status", "ok");
        }
        return result;
    }

    /**
     * 获取 DDIO 接口统计
     */
    @Override
    public List<DdioUrlStatusDTO> getDdioStatus(String thirdPartyId, String userToken) {
        List<DdioUrlStatusDTO> ddioUrlStatusDtoS = new ArrayList<>();

        ThirdParty thirdParty = ddioService.getThirdParty(thirdPartyId);
        DdioUrlStatusDTO accessTokenStatus = getAccessTokenStatus(thirdParty);

        ddioUrlStatusDtoS.add(accessTokenStatus);
        // access_token 获取都有问题，后面就不需要再测试了
        if (!DDIO_STATUS_OK.equals(accessTokenStatus.getStatus())) {
            return ddioUrlStatusDtoS;
        }

        // TODO 此处可以增加更多的 DDIO API 测试
        ddioUrlStatusDtoS.add(getAllUserStatus(thirdParty));
        ddioUrlStatusDtoS.add(getAllOrgStatus(thirdParty));
        ddioUrlStatusDtoS.add(getFriendsStatus(thirdParty, userToken));
        return ddioUrlStatusDtoS;
    }

    /**
     * 获取 access_token 接口状态
     */
    private DdioUrlStatusDTO getAccessTokenStatus(ThirdParty thirdParty) {
        ResponseEntity<String> responseEntity = DdioUtil.getAccessTokenResponse(thirdParty);

        if (!httpStatusIsOk(responseEntity)) {
            return new DdioUrlStatusDTO("AccessToken", DDIO_STATUS_HTTP_REQUEST_FAILED, "");
        }

        if (!doodCodeIsOk(responseEntity)) {
            return new DdioUrlStatusDTO("AccessToken", DDIO_STATUS_REQUEST_FAILED, getDoodMsg(responseEntity));
        }

        List<String> errorParams = new ArrayList<>();

        if (!StringUtils.isEmpty(checkResultStr(responseEntity, ACCESS_TOKEN))) {
            errorParams.add(ACCESS_TOKEN);
        }

        if (!errorParams.isEmpty()) {
            return new DdioUrlStatusDTO("AccessToken", DDIO_STATUS_RESPONSE_PARAM_ERROR, StringUtils.join(errorParams, "|"));
        }
        return new DdioUrlStatusDTO("AccessToken", DDIO_STATUS_OK, "");
    }

    /**
     * 获取所有用户接口状态
     */
    private DdioUrlStatusDTO getAllUserStatus(ThirdParty thirdParty) {
        ResponseEntity<String> responseEntity = DdioUtil.getAllUserResponse(thirdParty, tokenService.accessToken(thirdParty), 1, 10);
        if (!httpStatusIsOk(responseEntity)) {
            return new DdioUrlStatusDTO("getAllUser", DDIO_STATUS_HTTP_REQUEST_FAILED, "");
        }

        if (!doodCodeIsOk(responseEntity)) {
            return new DdioUrlStatusDTO("getAllUser", DDIO_STATUS_REQUEST_FAILED, getDoodMsg(responseEntity));
        }

        DdioResponseBody resp = JSON.parseObject(responseEntity.getBody(), DdioResponseBody.class);
        if (resp == null || resp.getUserSet().isEmpty()) {
            return new DdioUrlStatusDTO("getAllUser", DDIO_STATUS_RESPONSE_PARAM_EMPTY, "");
        }

        return new DdioUrlStatusDTO("getAllUser", DDIO_STATUS_OK, "");
    }

    /**
     * 获取所有组织接口状态
     */
    private DdioUrlStatusDTO getAllOrgStatus(ThirdParty thirdParty) {
        ResponseEntity<String> responseEntity = DdioUtil.getAllOrgResponse(thirdParty, tokenService.accessToken(thirdParty));
        if (!httpStatusIsOk(responseEntity)) {
            return new DdioUrlStatusDTO("getAllOrg", DDIO_STATUS_HTTP_REQUEST_FAILED, "");
        }

        if (!doodCodeIsOk(responseEntity)) {
            return new DdioUrlStatusDTO("getAllOrg", DDIO_STATUS_REQUEST_FAILED, getDoodMsg(responseEntity));
        }

        DdioResponseBody resp = JSON.parseObject(responseEntity.getBody(), DdioResponseBody.class);
        if (resp == null || resp.getOrgList().isEmpty()) {
            return new DdioUrlStatusDTO("getAllOrg", DDIO_STATUS_RESPONSE_PARAM_EMPTY, "");
        }

        return new DdioUrlStatusDTO("getAllOrg", DDIO_STATUS_OK, "");
    }

    /**
     * 获取所有好友接口状态
     */
    private DdioUrlStatusDTO getFriendsStatus(ThirdParty thirdParty, String userToken) {
        ResponseEntity<String> responseEntity = DdioUtil.getAllBuddysResponse(thirdParty, userToken, tokenService.accessToken(thirdParty));
        if (!httpStatusIsOk(responseEntity)) {
            return new DdioUrlStatusDTO("getFriends", DDIO_STATUS_HTTP_REQUEST_FAILED, "");
        }

        if (!doodCodeIsOk(responseEntity)) {
            return new DdioUrlStatusDTO("getFriends", DDIO_STATUS_REQUEST_FAILED, getDoodMsg(responseEntity));
        }

        List<Object> friendResult = JsonPath.parse(responseEntity.getBody()).read("$.result");
        List<DoodFriendsDTO> friends = JSONObject.parseArray(JSONObject.toJSONString(friendResult), DoodFriendsDTO.class);
        if (friends.isEmpty()) {
            return new DdioUrlStatusDTO("getFriends", DDIO_STATUS_RESPONSE_PARAM_EMPTY, "");
        }

        return new DdioUrlStatusDTO("getFriends", DDIO_STATUS_OK, "");
    }

    /**
     * 验证 DDIO 结果中是否存在指定字段
     */
    private String checkResultStr(ResponseEntity<String> entity, String str) {
        try {
            getResultParam(entity, str);
        } catch (Exception e) {
            return str;
        }
        return "";
    }

    /**
     * 获取返回 result 中的某个 String 字段
     */
    private String getResultParam(ResponseEntity<String> entity, String param) {
        return JsonPath.parse(entity.getBody()).read("$.result." + param);
    }

    /**
     * 判断 http status 是否正确
     */
    private boolean httpStatusIsOk(ResponseEntity<String> entity) {
        boolean isOk = false;
        if (HttpStatus.OK.equals(entity.getStatusCode())) {
            isOk = true;
        }
        return isOk;
    }

    /**
     * 消息体中的 code 是否为 0
     */
    private boolean doodCodeIsOk(ResponseEntity<String> entity) {
        boolean isOk = false;
        Integer code = JsonPath.parse(entity.getBody()).read("$.code");
        if (Objects.equals(code, 0)) {
            isOk = true;
        }
        return isOk;
    }

    /**
     * 获取 dood 接口返回中的 msg
     */
    private String getDoodMsg(ResponseEntity<String> entity) {
        return JsonPath.parse(entity.getBody()).read("$.msg");
    }

}
